home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / DEMOS / WALKER / walkviewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  12.9 KB  |  494 lines

  1. /*
  2.  * walkviewer.c [from agviewer.c  (version 1.0)]
  3.  *
  4.  * AGV: a glut viewer. Routines for viewing a 3d scene w/ glut
  5.  *
  6.  * See agv_example.c and agviewer.h comments within for more info.
  7.  *
  8.  * I welcome any feedback or improved versions!
  9.  *
  10.  * Philip Winston - 4/11/95
  11.  * pwinston@hmc.edu
  12.  * http://www.cs.hmc.edu/people/pwinston
  13.  */
  14.  
  15. #include <GL/glut.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <math.h>
  19.  
  20. #include "walkviewer.h"
  21.  
  22. /***************************************************************/
  23. /************************** SETTINGS ***************************/
  24. /***************************************************************/
  25.  
  26.    /* Initial polar movement settings */
  27. #define INIT_POLAR_AZ  0.0
  28. #define INIT_POLAR_EL 30.0
  29. #define INIT_DIST      3.0
  30. #define INIT_AZ_SPIN   0.5
  31. #define INIT_EL_SPIN   0.0
  32.  
  33.   /* Initial flying movement settings */
  34. #define INIT_EX        0.0
  35. #define INIT_EY       -2.0
  36. #define INIT_EZ       -2.0
  37. #define INIT_MOVE     0.01
  38. #define MINMOVE      0.001    
  39.  
  40.   /* Start in this mode */
  41. #define INIT_MODE   POLAR   
  42.  
  43.   /* Controls:  */
  44.  
  45.   /* map 0-9 to an EyeMove value when number key is hit in FLYING mode */
  46. #define SPEEDFUNCTION(x) ((x)*(x)*0.001)  
  47.  
  48.   /* Multiply EyeMove by (1+-MOVEFRACTION) when +/- hit in FLYING mode */
  49. #define MOVEFRACTION 0.25   
  50.  
  51.   /* What to multiply number of pixels mouse moved by to get rotation amount */
  52. #define EL_SENS   0.5
  53. #define AZ_SENS   0.5
  54.  
  55.   /* What to multiply number of pixels mouse moved by for movement amounts */
  56. #define DIST_SENS 0.01
  57. #define E_SENS    0.01
  58.  
  59.   /* Minimum spin to allow in polar (lower forced to zero) */
  60. #define MIN_AZSPIN 0.1
  61. #define MIN_ELSPIN 0.1
  62.  
  63.   /* Factors used in computing dAz and dEl (which determine AzSpin, ElSpin) */
  64. #define SLOW_DAZ 0.90
  65. #define SLOW_DEL 0.90
  66. #define PREV_DAZ 0.80
  67. #define PREV_DEL 0.80
  68. #define CUR_DAZ  0.20
  69. #define CUR_DEL  0.20
  70.  
  71. /***************************************************************/
  72. /************************** GLOBALS ****************************/
  73. /***************************************************************/
  74.  
  75. int     MoveMode = INIT_MODE;  /* FLYING or POLAR mode? */
  76.  
  77. GLfloat Ex = INIT_EX,             /* flying parameters */
  78.         Ey = INIT_EY,
  79.         Ez = INIT_EZ,
  80.         EyeMove = INIT_MOVE,     
  81.  
  82.         EyeDist = INIT_DIST,      /* polar params */
  83.         AzSpin  = INIT_AZ_SPIN,
  84.         ElSpin  = INIT_EL_SPIN,
  85.  
  86.         EyeAz = INIT_POLAR_AZ,    /* used by both */
  87.         EyeEl = INIT_POLAR_EL;
  88.  
  89. int agvMoving;    /* Currently moving?  */
  90.  
  91. int downx, downy,   /* for tracking mouse position */
  92.     lastx, lasty,
  93.     downb = -1;     /* and button status */
  94.                         
  95. GLfloat downDist, downEl, downAz, /* for saving state of things */
  96.         downEx, downEy, downEz,   /* when button is pressed */
  97.         downEyeMove;                
  98.  
  99. GLfloat dAz, dEl, lastAz, lastEl;  /* to calculate spinning w/ polar motion */
  100. int     AdjustingAzEl = 0;
  101.  
  102. int AllowIdle, RedisplayWindow; 
  103.    /* If AllowIdle is 1 it means AGV will install its own idle which
  104.     * will update the viewpoint as needed and send glutPostRedisplay() to the
  105.     * window RedisplayWindow which was set in agvInit().  AllowIdle of 0
  106.     * means AGV won't install an idle funciton, and something like
  107.     * "if (agvMoving) agvMove()" should exist at the end of the running
  108.     * idle function.
  109.     */
  110.  
  111. /* Some <math.h> files do not define M_PI... */
  112. #ifndef M_PI
  113. #define M_PI            3.14159265358979323846
  114. #endif
  115. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  116. #define TORAD(x) ((M_PI/180.0)*(x))
  117. #define TODEG(x) ((180.0/M_PI)*(x))
  118.  
  119. /***************************************************************/
  120. /************************ PROTOTYPES ***************************/
  121. /***************************************************************/
  122.  
  123.   /*
  124.    * these are functions meant for internal use only
  125.    * the other prototypes are in agviewer.h
  126.    */
  127.  
  128. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth);
  129. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z, GLfloat az, GLfloat el);
  130. int  ConstrainEl(void);
  131. void MoveOn(int v);
  132. void SetMove(float newmove);
  133. void normalize(GLfloat v[3]);
  134. void ncrossprod(float v1[3], float v2[3], float cp[3]);
  135.  
  136.  
  137. /***************************************************************/
  138. /************************ agvInit ******************************/
  139. /***************************************************************/
  140.  
  141. void agvInit(int window)
  142. {
  143.   glutMouseFunc(agvHandleButton);
  144.   glutMotionFunc(agvHandleMotion);
  145.   glutKeyboardFunc(agvHandleKeys);
  146.   RedisplayWindow = glutGetWindow();
  147.   agvSetAllowIdle(window);
  148. }
  149.  
  150. /***************************************************************/
  151. /************************ VIEWPOINT STUFF **********************/
  152. /***************************************************************/
  153.  
  154.   /*
  155.    * viewing transformation modified from page 90 of red book
  156.    */
  157. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth)
  158. {
  159.   glTranslatef(0, 0, -dist);
  160.   glRotatef(elevation, 1, 0, 0);
  161.   glRotatef(azimuth, 0, 1, 0);
  162.  
  163. }
  164.  
  165.   /*
  166.    * I took the idea of tracking eye position in absolute
  167.    * coords and direction looking in Polar form from denis
  168.    */
  169. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z, GLfloat az, GLfloat el)
  170. {
  171.   float lookat[3], perp[3], up[3];
  172.  
  173.   lookat[0] = sin(TORAD(az))*cos(TORAD(el));
  174.   lookat[1] = sin(TORAD(el));
  175.   lookat[2] = -cos(TORAD(az))*cos(TORAD(el));
  176.   normalize(lookat);
  177.   perp[0] = lookat[2];
  178.   perp[1] = 0;
  179.   perp[2] = -lookat[0];
  180.   normalize(perp);
  181.   ncrossprod(lookat, perp, up);
  182.   gluLookAt(x, y, z,
  183.             x+lookat[0], y+lookat[1], z+lookat[2],
  184.             up[0], up[1], up[2]);
  185. }
  186.  
  187.   /*
  188.    * Call viewing transformation based on movement mode
  189.    */
  190. void agvViewTransform(void)
  191.   switch (MoveMode) {
  192.     case FLYING:
  193.       FlyLookFrom(Ex, Ey, Ez, EyeAz, EyeEl);
  194.       break;
  195.     case POLAR:
  196.       PolarLookFrom(EyeDist, EyeEl, EyeAz);
  197.       break;
  198.     }
  199. }
  200.  
  201.   /*
  202.    * keep them vertical; I think this makes a lot of things easier, 
  203.    * but maybe it wouldn't be too hard to adapt things to let you go
  204.    * upside down
  205.    */
  206. int ConstrainEl(void)
  207. {
  208.   if (EyeEl <= -90) {
  209.     EyeEl = -89.99;
  210.     return 1;
  211.   } else if (EyeEl >= 90) {
  212.     EyeEl = 89.99;
  213.     return 1;
  214.   }
  215.   return 0;
  216. }
  217.  
  218.  /*
  219.   * Idle Function - moves eyeposition
  220.   */
  221. void agvMove(void)
  222. {
  223.  
  224.   switch (MoveMode)  {
  225.     case FLYING:
  226.       Ex += EyeMove*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  227.       Ey += EyeMove*sin(TORAD(EyeEl));
  228.       Ez -= EyeMove*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  229.       break;
  230.  
  231.     case POLAR:
  232.       EyeEl += ElSpin;
  233.       EyeAz += AzSpin;
  234.       if (ConstrainEl()) {  /* weird spin thing to make things look     */
  235.         ElSpin = -ElSpin;      /* look better when you are kept from going */
  236.                                /* upside down while spinning - Isn't great */
  237.         if (fabs(ElSpin) > fabs(AzSpin))
  238.           AzSpin = fabs(ElSpin) * ((AzSpin > 0) ? 1 : -1);
  239.       }
  240.       break;
  241.     }
  242.  
  243.   if (AdjustingAzEl) {
  244.     dAz *= SLOW_DAZ;
  245.     dEl *= SLOW_DEL;
  246.   }
  247.  
  248.   if (AllowIdle) {
  249.     glutPostWindowRedisplay(RedisplayWindow);
  250.   }
  251. }
  252.  
  253.  
  254.   /*
  255.    * Don't install agvMove as idle unless we will be updating the view
  256.    * and we've been given a RedisplayWindow
  257.    */
  258. void MoveOn(int v)
  259. {
  260.   if (v && ((MoveMode == FLYING && EyeMove != 0) ||
  261.              (MoveMode == POLAR &&
  262.              (AzSpin != 0 || ElSpin != 0 || AdjustingAzEl)))) {
  263.     agvMoving = 1;
  264.     if (AllowIdle)
  265.       glutIdleFunc(agvMove);
  266.   } else {
  267.     agvMoving = 0;
  268.     if (AllowIdle)
  269.       glutIdleFunc(NULL);
  270.   }
  271. }
  272.  
  273.   /*
  274.    * set new redisplay window.  If <= 0 it means we are not to install
  275.    * an idle function and will rely on whoever does install one to 
  276.    * put statement like "if (agvMoving) agvMove();" at end of it
  277.    */
  278. void agvSetAllowIdle(int allowidle)
  279. {
  280.   if ((AllowIdle = allowidle))
  281.     MoveOn(1);
  282. }
  283.  
  284.  
  285.   /*
  286.    * when moving to flying we stay in the same spot, moving to polar we
  287.    * reset since we have to be looking at the origin (though a pivot from
  288.    * current position to look at origin might be cooler)
  289.    */
  290. void agvSwitchMoveMode(int move)
  291. {
  292.   switch (move) {
  293.     case FLYING:
  294.       Ex    = -EyeDist*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  295.       Ey    =  EyeDist*sin(TORAD(EyeEl));
  296.       Ez    =  EyeDist*(cos(TORAD(EyeAz))*cos(TORAD(EyeEl)));
  297.       EyeAz =  EyeAz;
  298.       EyeEl = -EyeEl;
  299.       EyeMove = INIT_MOVE;
  300.       break;
  301.     case POLAR:
  302.       EyeDist = INIT_DIST;
  303.       EyeAz   = INIT_POLAR_AZ;
  304.       EyeEl   = INIT_POLAR_EL;
  305.       AzSpin  = INIT_AZ_SPIN;
  306.       ElSpin  = INIT_EL_SPIN;
  307.       break;
  308.     }
  309.   MoveMode = move;
  310.   MoveOn(1);
  311.   glutPostRedisplay();
  312. }
  313.  
  314. /***************************************************************/
  315. /*******************    MOUSE HANDLING   ***********************/
  316. /***************************************************************/
  317.  
  318. void agvHandleButton(int button, int state, int x, int y)
  319. {
  320.  if (state == GLUT_DOWN && downb == -1) {  
  321.     lastx = downx = x;
  322.     lasty = downy = y;
  323.     downb = button;    
  324.  
  325.     switch (button) {
  326.       case GLUT_LEFT_BUTTON:
  327.         lastEl = downEl = EyeEl;
  328.         lastAz = downAz = EyeAz;
  329.         AzSpin = ElSpin = dAz = dEl = 0;
  330.         AdjustingAzEl = 1;
  331.     MoveOn(1);
  332.         break;
  333.  
  334.       case GLUT_MIDDLE_BUTTON:
  335.         downDist = EyeDist;
  336.     downEx = Ex;
  337.     downEy = Ey;
  338.     downEz = Ez;
  339.     downEyeMove = EyeMove;
  340.     EyeMove = 0;
  341.     }
  342.  
  343.   } else if (state == GLUT_UP && button == downb) {
  344.  
  345.     downb = -1;
  346.  
  347.     switch (button) {
  348.       case GLUT_LEFT_BUTTON:
  349.         if (MoveMode != FLYING) {
  350.       AzSpin =  -dAz;
  351.       if (AzSpin < MIN_AZSPIN && AzSpin > -MIN_AZSPIN)
  352.         AzSpin = 0;    
  353.       ElSpin = -dEl;
  354.       if (ElSpin < MIN_ELSPIN && ElSpin > -MIN_ELSPIN)
  355.         ElSpin = 0; 
  356.     }
  357.         AdjustingAzEl = 0;
  358.         MoveOn(1);
  359.     break;
  360.  
  361.       case GLUT_MIDDLE_BUTTON:
  362.     EyeMove = downEyeMove;
  363.       }
  364.   }
  365. }
  366.  
  367.  /*
  368.   * change EyeEl and EyeAz and position when mouse is moved w/ button down
  369.   */
  370. void agvHandleMotion(int x, int y)
  371. {
  372.   int deltax = x - downx, deltay = y - downy;
  373.  
  374.   switch (downb) {
  375.     case GLUT_LEFT_BUTTON:
  376.       EyeEl  = downEl + EL_SENS * ((MoveMode == FLYING) ? -deltay : deltay);
  377.       ConstrainEl();
  378.       EyeAz  = downAz + AZ_SENS * deltax;
  379.       dAz    = PREV_DAZ*dAz + CUR_DAZ*(lastAz - EyeAz);
  380.       dEl    = PREV_DEL*dEl + CUR_DEL*(lastEl - EyeEl);
  381.       lastAz = EyeAz;
  382.       lastEl = EyeEl;
  383.       break;
  384.     case GLUT_MIDDLE_BUTTON:
  385.         EyeDist = downDist + DIST_SENS*deltay;
  386.         Ex = downEx - E_SENS*deltay*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  387.         Ey = downEy - E_SENS*deltay*sin(TORAD(EyeEl));
  388.         Ez = downEz + E_SENS*deltay*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  389.       break;
  390.   }
  391.   glutPostRedisplay();
  392. }
  393.  
  394. /***************************************************************/
  395. /********************* KEYBOARD HANDLING ***********************/
  396. /***************************************************************/
  397.  
  398.   /*
  399.    * set EyeMove (current speed) for FLYING mode
  400.    */
  401. void SetMove(float newmove)
  402. {
  403.   if (newmove > MINMOVE) {
  404.     EyeMove = newmove;
  405.     MoveOn(1);
  406.   } else {
  407.     EyeMove = 0;
  408.     MoveOn(0);
  409.   }
  410. }
  411.  
  412.   /*
  413.    * 0->9 set speed, +/- adjust current speed  -- in FLYING mode
  414.    */
  415. /* ARGSUSED1 */
  416. void agvHandleKeys(unsigned char key, int x, int y)
  417. {
  418.   if (MoveMode != FLYING)
  419.     return;
  420.  
  421.   if (key >= '0' && key <= '9')
  422.     SetMove(SPEEDFUNCTION((key-'0')));
  423.   else
  424.     switch(key) {
  425.       case '+':  
  426.         if (EyeMove == 0)
  427.           SetMove(MINMOVE);
  428.          else
  429.       SetMove(EyeMove *= (1 + MOVEFRACTION));
  430.         break;
  431.       case '-':
  432.     SetMove(EyeMove *= (1 - MOVEFRACTION));
  433.         break;
  434.     }
  435. }
  436.  
  437. /***************************************************************/
  438. /*********************** VECTOR STUFF **************************/
  439. /***************************************************************/
  440.  
  441.   /* normalizes v */
  442. void normalize(GLfloat v[3])
  443. {
  444.   GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  445.  
  446.   if (d == 0)
  447.     fprintf(stderr, "Zero length vector in normalize\n");
  448.   else
  449.     v[0] /= d; v[1] /= d; v[2] /= d;
  450. }
  451.  
  452.   /* calculates a normalized crossproduct to v1, v2 */
  453. void ncrossprod(float v1[3], float v2[3], float cp[3])
  454. {
  455.   cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
  456.   cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
  457.   cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
  458.   normalize(cp);
  459. }
  460.  
  461. /***************************************************************/
  462. /**************************** AXES *****************************/
  463. /***************************************************************/
  464.  
  465.  
  466.   /* draw axes -- was helpful to debug/design things */
  467. void agvMakeAxesList(int displaylistnum)
  468. {
  469.   int i,j;
  470.   GLfloat axes_ambuse[] =   { 0.5, 0.0, 0.0, 1.0 };
  471.   glNewList(displaylistnum, GL_COMPILE);
  472.   glPushAttrib(GL_LIGHTING_BIT);
  473.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, axes_ambuse);
  474.     glBegin(GL_LINES);
  475.       glVertex3f(15, 0, 0); glVertex3f(-15, 0, 0);
  476.       glVertex3f(0, 15, 0); glVertex3f(0, -15, 0);
  477.       glVertex3f(0, 0, 15); glVertex3f(0, 0, -15);
  478.     glEnd();
  479.     for (i = 0; i < 3; i++) {
  480.       glPushMatrix();
  481.         glTranslatef(-10*(i==0), -10*(i==1), -10*(i==2));
  482.         for (j = 0; j < 21; j++) {
  483.           glutSolidCube(0.1);
  484.           glTranslatef(i==0, i==1, i==2);
  485.     }
  486.       glPopMatrix();
  487.     }
  488.   glPopAttrib();
  489.   glEndList();  
  490. }
  491.  
  492.  
  493.